import { ExclamationCircleFilled } from '@ant-design/icons';
import { useRequest } from 'ahooks';
import { Form, Layout, message, Modal, Spin } from 'antd';
import { isEmpty, trim } from 'lodash-es';
import React, { useCallback, useEffect, useRef, useState } from 'react';
import Editor from './components/Editor';
import {
  DEFAULT_SCREEN_SIZE,
  LayerTypeBE
} from './components/Editor/components/TemplateEffect/constant';
// 需要组件export的函数
import {
  getBELayerRatioInfo,
  getShapeImageKey,
  transferToBELayersInfo,
  transferToFELayersInfo
} from './components/Editor/components/TemplateEffect/utils';
import Footer from './components/Footer';
import Header from './components/Header';
import { IsDraft, OperationType } from './constant';
import styles from './index.module.less';
import {
  Info,
  LayerInfoFE,
  RealTimePreviewProps,
  ScreenRefType,
  TemplateDetailInfoBE
} from './interface';
import {
  addRealTimePreviewParams,
  handleRefresh,
  hasEmptyContentTextLayer,
  hasEmptyImageLayer,
  hasEmptyProductLayer,
  mergeRealTimePreviewData
} from './utils';

let canLeave = false;

const TemplateEditor = (

): JSX.Element => {
  const leavePage = useCallback((): void => {
    canLeave = true;
  }, [history]);

  const [canSave, setCanSave] = useState(true);
  const [templateDetail, setTemplateDetail] = useState<
    Partial<TemplateDetailInfoBE>
  >({
    layers: []
  });
  const feLayersRef = useRef<LayerInfoFE[]>();
  const [loading, setLoading] = useState(false);
  const operationType: OperationType = OperationType.Create;

  const [screenSize, setScreenSize] = useState(DEFAULT_SCREEN_SIZE);
  const screenRef: ScreenRefType = useRef();
  const [infoForm] = Form.useForm<Info>();

  const { runAsync: realTimePreview } = useRequest(
    async (props: RealTimePreviewProps): Promise<LayerInfoFE[]> => {
      const { layers, alignLatestLayers = true } = props;
      const needRealTimePreviewLayers = layers.filter(
        (layer) => layer.data.type === LayerTypeBE.Text && !layer.data.isHidden
      );

      // 空数组不发送请求，防止后端报错
      if (isEmpty(needRealTimePreviewLayers)) {
        return alignLatestLayers ? feLayersRef.current : layers;
      }

      // 等待合并新数据的 layers
      let newLayersInfo = alignLatestLayers ? feLayersRef.current : layers;

      const requestBody = addRealTimePreviewParams({
        requestBody: {
          layers: transferToBELayersInfo(needRealTimePreviewLayers),
          templateSize: screenSize
        }
      });
      return newLayersInfo;
    },
    {
      manual: true,
      debounceWait: 300
    }
  );

  const saveTemplateInfo = async (isDraft: IsDraft): Promise<void> => {
    // save draft 与 正式 save 的共同校验部分，放在一起
    if (hasEmptyImageLayer(templateDetail.feLayers || [])) {
      message.error('No content in image layer.');
      return;
    }

    if (hasEmptyContentTextLayer(templateDetail.feLayers || [])) {
      message.error('No content in text layer.');
      return;
    }

    const newTemplateDetail = {} as any;
    let shapeImagesKeys = [];

    newTemplateDetail.isDraft = isDraft;
    newTemplateDetail.templateName = trim(templateDetail.templateName);
    newTemplateDetail.templateSize = screenSize;

    if (isEmpty(templateDetail.feLayers)) {
      // save as draft 的时候，如果 feLayers 没有值，传 null
      newTemplateDetail.layers = null;
      newTemplateDetail.layerInfo = {};
    } else {
      try {
        shapeImagesKeys = await getShapeImageKey(
          screenRef.current.getCurrentLayers(templateDetail.feLayers)
        );
      } catch (error) {
        message.error('Upload shape image error, please try again.');
        return;
      }

      newTemplateDetail.layers = transferToBELayersInfo(
        templateDetail.feLayers,
        shapeImagesKeys
      );

      newTemplateDetail.layerInfo = getBELayerRatioInfo(
        templateDetail.feLayers
      );
    }
  };

  const saveAsDraft = async (): Promise<void> => {
    try {
      await infoForm.validateFields();
    } catch (error) {
      message.error('Template name error, please check again.');
      return;
    }

    if (hasEmptyProductLayer(templateDetail.feLayers || [])) {
      message.error('No content in product image layer.');
      return;
    }

    await saveTemplateInfo(IsDraft.IsDraft);
  };

  const handleLeave = (): boolean => {
    if (!canLeave) {
      Modal.confirm({
        title: 'Are you sure you want to leave?',
        content: 'If so, would you like to save it as a draft?',
        cancelText: 'Discard',
        okText: 'Save as draft',
        okButtonProps: { disabled: !canSave },
        centered: true,
        closable: true,
        maskClosable: true,
        icon: <ExclamationCircleFilled />,
        width: 480,
        onOk() {
          saveAsDraft();
        },
        cancelButtonProps: {
          onClick() {
            leavePage();
            Modal.destroyAll();
          }
        }
      });
      return false;
    } else {
      canLeave = false;
      return true;
    }
  };

  useEffect(() => {
    feLayersRef.current = templateDetail.feLayers;
  }, [templateDetail.feLayers]);

  useEffect(() => {
    window.addEventListener('beforeunload', handleRefresh, false);
    return (): void => {
      window.removeEventListener('beforeunload', handleRefresh);
    };
  }, []);

  return (
    <Spin spinning={loading} wrapperClassName={styles.spin}>
      <Layout className="w-full flex flex-col h-full">
        <Header operationType={operationType} onLeave={handleLeave} />
        <Editor
          ref={screenRef}
          infoForm={infoForm}
          screenSize={screenSize}
          templateDetail={templateDetail}
          operationType={operationType}
          setScreenSize={setScreenSize}
          realTimePreview={realTimePreview}
          onTemplateDetailChange={setTemplateDetail}
        />
        <Footer
          canSave={canSave}
          infoForm={infoForm}
          templateDetail={templateDetail}
          onLeave={handleLeave}
          saveTemplateInfo={saveTemplateInfo}
        />
      </Layout>
    </Spin>
  );
};

export default TemplateEditor;
